﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BE;

namespace BLL
{
	public class Graph
	{
		public SortedDictionary<string, EdgeGraph> Edges { get; private set; }
		public SortedDictionary<int, GraphVertex> Vertices { get; private set; }

		public Graph()
		{
		}

		public void FillGraph( SortedDictionary<int, Vertex> ver, List<Edge> edg )
		{
			Initialize();
			foreach ( Edge e in edg )
			{
				EdgeGraph eg = new EdgeGraph( e, ver[e.L1], ver[e.L2] );
				AddEdge( eg );
				//adjacency graph so that you can also go from X to Y instead of only form Y to X
				if ( eg.Straight )
				{
					EdgeGraph egClone = eg.CloneMe();
					egClone.V1 = eg.V2;
					egClone.V2 = eg.V1;
					egClone.L1 = eg.L2;
					egClone.L2 = eg.L1;
					AddEdge( egClone );
				}
			}
		}

		public List<Edge> GetPath( Room start, Room end )
		{
			List<Edge> EdgePaths = new List<Edge>();
			EdgeGraph current;
			Edges.TryGetValue( start.LocationID + "$" + end.LocationID, out current );
			EdgePaths.Add( current.ToEdge() );
			while ( current.L2 != end.LocationID ){
				Edges.TryGetValue( current.L2 + "$" + end.LocationID, out current );
				EdgePaths.Add( current.ToEdge() );
			} 
			return EdgePaths;
		}

		public void UpdateGraph( SortedDictionary<int, Vertex> Vertices, List<Edge> edges )
		{
			FillGraph( Vertices, edges );
			CalculateShortestPaths();
		}

		public List<string> getDirections( List<Edge> edges )
		{
			List<string> directions = new List<string>();
			for ( int i = 0; i < edges.Count; i++ )
			{
				if ( i == 0 )
				{
					string direction = "Start with the following action: " + edges[i].Direction;
					if ( edges[i].Straight )
					{
						RoomWorker rw = new RoomWorker();
						List<Room> rooms = rw.GetRoomsByLocation( edges[i].L2 );
						direction += " passing the rooms:";
						foreach ( Room r in rooms )
						{
							direction += " " + r.Name;
						}
					}
					
					directions.Add( direction );
				}
				else if ( !( edges[i - 1].Straight && edges[i].Straight ) )
					directions.Add( edges[i].Direction );
			}
			directions.Add( "You should now be located at your desired destination" );
			return directions;
		}

		private void Initialize()
		{
			Edges = new SortedDictionary<string, EdgeGraph>();
			Vertices = new SortedDictionary<int, GraphVertex>();
		}

		private void AddEdge( EdgeGraph e )
		{
			if ( !Edges.ContainsKey( e.GetTreeID ) )
			Edges.Add( e.GetTreeID, e );
			try
			{
				AddVertex( e.V1 );
			}
			finally { }
			{
				//throw ex;
			}
			try
			{
				AddVertex( e.V2 );
			}
			finally { }
		}

		private void AddVertex( GraphVertex v )
		{
			if ( !Vertices.ContainsKey( v.ID ) )
				Vertices.Add( v.ID, v );
		}

		public void CalculateShortestPaths()
		{
			foreach ( GraphVertex i in Vertices.Values)
			{
				foreach ( GraphVertex j in Vertices.Values )
				{
					foreach ( GraphVertex k in Vertices.Values)
					{
						if ( Edges.ContainsKey( i.ID + "$" + k.ID ) && Edges.ContainsKey( k.ID + "$" + j.ID ) && i.ID != j.ID)
						{
							EdgeGraph ik;
							EdgeGraph kj;
							Edges.TryGetValue( i.ID + "$" + k.ID, out ik );
							Edges.TryGetValue( k.ID + "$" + j.ID, out kj );
							ik = ik.CloneMe();
							
							kj = kj.CloneMe();
							if ( Edges.ContainsKey( i.ID + "$" + j.ID ) )
							{
								
								EdgeGraph ij;
								Edges.TryGetValue( i.ID + "$" + j.ID, out ij );
								ij = ij.CloneMe();
								//if the ik->kj road is shorter than the ij road replace edge at ij with ik edge
								if ( ij.TotalWeight > kj.TotalWeight + ik.TotalWeight )
								{
									ik.TotalWeight += kj.TotalWeight;
									Edges.Remove( i.ID + "$" + j.ID );
									Edges.Add( i.ID + "$" + j.ID, ik );

								}

							}
							else
							{
								ik.TotalWeight += kj.TotalWeight;
								if ( Edges.ContainsKey( i.ID + "$" + j.ID ) )
									Edges.Remove( i.ID + "$" + j.ID );
								Edges.Add( i.ID + "$" + j.ID, ik );

							}
						}
					}
				}
			}
		}
	}
}
